source('../settings/settings.R')
source('commonFunctions.R')
persons <- SELECTED_SUBJECTS
all_Drive4 <- read.csv('../data/processed/distancewise/TT1_Drive_4_30m_30m.csv')
all_Drive4$Subject <- as.factor(all_Drive4$Subject)
all_Drive4$logPerspiration <- log(all_Drive4$Perspiration)
# starting_points = c( 669 , 668 , 676 , 687 , 680 , 676 , 678 ,
# 693 , 722 , 723 , 677 , 679 , 711 , 707 ,
# 699 , 679 , 684 , 688 , 686 , 696 , 702 )
#
# ending_points = c( 741 , 786 , 749 , 782 , 736 , 756 , 768 ,
# 812 , 853 , 792 , 783 , 772 , 799 , 781 ,
# 777 , 763 , 795 , 791 , 832 , 755 , 758 )
peak_points = c( 67 , 86 , 73 , 73 , 73 , 64 , 73 ,
79 , 69 , 64 , 68 , 67 , 77 , 68 ,
82 , 67 , 72 , 72 , 71 , 68 , 64 )
# Driving time
driving_times = vector(mode="list", length = length(persons))
names(driving_times) <- persons
activity_names = vector(mode="list", length = length(persons))
names(activity_names) <- persons
acc_start_times = vector(mode="list", length = length(persons))
names(acc_start_times) <- persons
acc_end_times = vector(mode="list", length = length(persons))
names(acc_end_times) <- persons
stressor_start_times = vector(mode="list", length = length(persons))
names(stressor_start_times) <- persons
stressor_end_times = vector(mode="list", length = length(persons))
names(stressor_end_times) <- persons
complete_times = vector(mode="list", length = length(persons))
names(complete_times) <- persons
data_baseline = vector(mode="list", length=length(persons))
pp_baseline = vector(mode="list", length=length(persons))
names(data_baseline) <- persons
names(pp_baseline) <- persons
# Number of peaks
PREV_DISTANCE = 600
TRACKING_DISTANCE = 150
DRIVE_MODE = 4
getActivityName <- function(x, fullname=F) {
if(x == 1) return(ifelse(fullname, "Normal", "NO"))
if(x == 2) return(ifelse(fullname, "Cognitive", "C"))
if(x == 3) return(ifelse(fullname, "Motoric", "M"))
}
for (p in persons) {
pData <- all_Drive4[all_Drive4$Subject==as.integer(p) | all_Drive4$Subject==p,]
pAcc <- pData[pData$Failure>0.5,] # Failure = 1
acc_start_times[[p]] <- min(pAcc$Distance)
acc_end_times[[p]] <- max(pAcc$Distance)
activity_names[[p]] <- getActivityName(pData[pData$Time==60,]$Activity, fullname = T)
pStressor = pData[pData$Activity>1.5,] # Stressor = 2, 3
if (nrow(pStressor) > 0) {
stressor_start_times[[p]] <- min(pStressor$Distance)
stressor_end_times[[p]] <- max(pStressor$Distance)
} else {
stressor_start_times[[p]] <- NULL
stressor_end_times[[p]] <- NULL
}
}
idx <- 1
plt_AllAcc <- vector(mode="list", length=length(persons))
names(plt_AllAcc) <- persons
COLOR_ACC = "#02A3C8"
COLOR_PP = "#F28E8E"
COLOR_BRAKE = "#888888"
y1 <- list(
tickfont = list(color = COLOR_ACC),
title="Degree",
range=c(0, 100)
)
y2 <- list(
tickfont = list(color = COLOR_PP),
overlaying = "y",
side = "right",
title = "Log Perspiration",
showgrid = FALSE,
range=c(min(all_Drive4$ppLogNormalized), max(all_Drive4$ppLogNormalized))
)
for (p in persons) {
pData <- all_Drive4[all_Drive4$Subject==as.integer(p) | all_Drive4$Subject==p,]
# Baseline
data_baseline[[p]] <- read.csv(str_interp("../data/processed/drives/T0${person}/T0${person}_Drive_1.csv", list(person=p)))
# Compute the mean
p_pp_nr <- data_baseline[[p]]$Perspiration
p_pp_nr <- p_pp_nr[!is.na(p_pp_nr)]
pp_baseline[[p]] <- log(mean(p_pp_nr))
# Incident
driving_times[[p]] <- max(pData$Distance)
incident_starting_time <- acc_start_times[[p]] # starting_points[idx]
incident_ending_time <- acc_end_times[[p]]
complete_times[[p]] <- ifelse(incident_starting_time + TRACKING_DISTANCE > driving_times[[p]], driving_times[[p]], incident_starting_time + TRACKING_DISTANCE)
from_time <- ifelse(incident_starting_time - PREV_DISTANCE >= 0, incident_starting_time - PREV_DISTANCE, 0)
to_time <- complete_times[[p]]
# print(paste("From", from_time))
# print(paste("Incident", incident_starting_time))
# print(paste("To", to_time))
pDataBefore <- pData[pData$Distance < incident_starting_time & pData$Distance >= from_time,]
pDataAfter <- pData[pData$Distance >= incident_starting_time & pData$Distance <= to_time,]
# print(nrow(pDataBefore))
# print(nrow(pDataAfter))
ppMeanBefore <- mean(pDataBefore$ppLogNormalized)
ppMeanAfter <- mean(pDataAfter$ppLogNormalized)
dir.create(file.path('../figures/drive/', paste0('Drive_', DRIVE_MODE)), showWarnings = FALSE)
fname <- str_interp('../figures/drive/Drive_${drive}/P${person}.svg', list(drive=DRIVE_MODE, person=p))
pData <- pData[pData$Distance >= from_time,]
plot_Acc <- plot_ly(pData, x = ~Distance, height=400, width=900) %>%
add_trace(name="Acceleration", y = ~Acceleration, type = 'scatter', mode = 'lines', line=list(width=1.5, color=COLOR_ACC)) %>%
add_trace(name="Brake", y = ~Braking, type = 'scatter', mode = 'lines', line=list(width=1.5, color=COLOR_BRAKE)) %>%
add_trace(name="PP", y = ~ppLogNormalized, type = 'scatter', mode = 'lines', line=list(width=1.5, color=COLOR_PP), yaxis = "y2") %>%
add_segments(x = min(pData$Distance), xend = max(pData$Distance), y = ppMeanBefore, yend = ppMeanBefore,
yaxis = "y2", name="Mean PP (Before Incident)",
line=list(color=COLOR_PP, dash = 'dot')) %>%
add_segments(x = min(pData$Distance), xend = max(pData$Distance), y = ppMeanAfter, yend = ppMeanAfter,
yaxis = "y2", name="Mean PP (After Incident)",
line=list(color="darkred", dash = 'dot')) %>%
# add_segments(x = min(pData$Distance) - 0.1, xend = max(pData$Distance), y = pp_baseline[[p]], yend = pp_baseline[[p]],
# yaxis = "y2", name="Baseline PP (from Drive 1)",
# line=list(color="blue", dash = 'dot')) %>%
layout(
title=paste0("Subject #", p, " (Stressor=", activity_names[[p]], ")"),
xaxis=list(title="Distance [m]", range=c(0)),
yaxis=y1,
yaxis2=y2,
margin = list(l = 50, r = 50, b = 50, t = 50, pad = 4),
shapes = list(
# Holistic period
list(type = "rect", fillcolor = "red",
line = list(color = "red"), opacity = 0.3,
x0 = incident_starting_time, x1 = incident_ending_time, xref = "x",
y0 = 0, y1 = 100, yref = "y"),
# Stressor period
list(type = "rect", fillcolor = "yellow",
line = list(color = "yellow"), opacity = 0.1,
x0 = stressor_start_times[[p]], x1 = incident_starting_time, xref = "x",
y0 = 0, y1 = 100, yref = "y"),
list(type = "rect", fillcolor = "yellow",
line = list(color = "yellow"), opacity = 0.1,
x0 = incident_ending_time, x1 = stressor_end_times[[p]], xref = "x",
y0 = 0, y1 = 100, yref = "y")
),
legend = list(x = 0.1, y = 1, bgcolor = "rgba(0,0,0,0)", title="Metric"),
autosize = F
)
# orca(plot_PP, fname)
idx <- idx + 1
plt_AllAcc[[p]] <- plot_Acc
}
htmltools::tagList(plt_AllAcc)
# for (p in persons) {
# # Save image
# orca(plt_AllAcc[[p]], file = paste0("../plots/drive/Drive_4/T0", p, ".png"), scale = 2)
# }
idx <- 1
behavioralColumns <- c("Subject",
"Brake_u",
"Brake_std",
"PP_before",
"PP_u",
"PP_std",
"PP_dev")
behavioralMatrix <- matrix(nrow=length(persons), ncol = length(behavioralColumns))
# Careful about Subject 09
# selected_persons <- persons[persons != "09"]
for (p in persons) {
pData <- all_Drive4[all_Drive4$Subject==as.integer(p) | all_Drive4$Subject==p,]
incident_starting_time <- acc_start_times[[p]] # starting_points[idx]
incident_ending_time <- acc_end_times[[p]]
from_time <- ifelse(incident_starting_time - PREV_DISTANCE >= 0, incident_starting_time - PREV_DISTANCE, 0)
to_time <- complete_times[[p]]
dfBefore <- pData[pData$Distance < incident_starting_time & pData$Distance >= from_time,]
dfAfter <- pData[pData$Distance >= incident_starting_time & pData$Distance <= to_time,]
# diffSpeed <- mean(dfAfter$Speed) - mean(dfBefore$Speed)
brakeMean <- mean(dfAfter$Braking)
brakeStd <- mean(dfAfter$Braking)
ppMean <- mean(dfAfter$ppLogNormalized)
ppBefore <- mean(dfBefore$ppLogNormalized)
ppStd <- sd(dfAfter$ppLogNormalized)
mid_avg <- (pp_baseline[[p]] + mean(dfBefore$ppLogNormalized)) / 2
diffPP <- mean(dfAfter$ppLogNormalized) - mean(dfBefore$ppLogNormalized)
behavioralMatrix[idx, ] <- c(p,
round(brakeMean, digits=5),
round(brakeStd, digits=5),
round(ppBefore, digits=5),
round(ppMean, digits = 5),
round(ppStd, digits=5),
round(diffPP, digits=5))
idx <- idx + 1
}
# behavioralMatrix
behavioralDf <- as.data.frame(behavioralMatrix)
names(behavioralDf) <- behavioralColumns
behavioralDf
NA
clusteringDf <- behavioralDf
clusteringDf$Subject <- NULL
# clusteringDf$PP_dev_norm <- as.numeric(clusteringDf$PP_dev) / as.numeric(clusteringDf$PP_u)
# clusteringDf$PP_std_norm <- as.numeric(clusteringDf$PP_std) / as.numeric(clusteringDf$PP_u)
clusteringDf$Brake_u <- NULL
clusteringDf$Brake_std <- NULL
clusteringDf$PP_before <- NULL
clusteringDf$PP_u <- NULL
clusteringDf$PP_std <- NULL
# clusteringDf$PP_dev <- NULL
rownames(clusteringDf) <- paste0("#", persons)
for (col in names(clusteringDf)) {
clusteringDf[,col] <- as.numeric(as.character(clusteringDf[, col]))
# clusteringDf[,col] <- scale(clusteringDf[,col])
}
clusteringDf
dfActivity <- all_Drive4[all_Drive4$Time==60,] %>% select(c("Subject", "Activity"))
dfActivity$ActivityName <- sapply(dfActivity$Activity, getActivityName)
dfActivity$Subject <- as.factor(dfActivity$Subject)
rownames(dfActivity) <- NULL
dfActivity %>% select(c("Subject", "ActivityName"))
library(dendextend)
NUMBER_OF_CLUSTERS = 3
color_darkpink = "#e75480"
CLUSTER_BRANCH_COLORS <- c("blue", "red", color_darkpink)[1:NUMBER_OF_CLUSTERS]
CLUSTER_LABEL_COLORS <- c("blue", "red", color_darkpink)[1:NUMBER_OF_CLUSTERS]
behavioralMatrixClustering <- as.matrix(clusteringDf)
rownames(behavioralMatrixClustering) <- paste0(dfActivity$ActivityName, " - #", persons)
distMatrix <- dist(behavioralMatrixClustering, method="manhattan")
hresults <- distMatrix %>% hclust
hc <- hresults %>%
as.dendrogram %>%
set("nodes_cex", NUMBER_OF_CLUSTERS) %>%
set("labels_col", value = CLUSTER_LABEL_COLORS, k=NUMBER_OF_CLUSTERS) %>%
# set("leaves_pch", 19) %>%
# set("leaves_col", value = c("gray"), k=NUMBER_OF_CLUSTERS) %>%
set("branches_k_color", value=CLUSTER_BRANCH_COLORS, k=NUMBER_OF_CLUSTERS)
plot(hc)
legend("topright",
title="Drive=Failure \nChange of Arousal",
legend = c("Exceptional Increase" , "Noticable Increase" , "No-change or Decrease"),
col = c("red", "pink" , "blue"),
pch = c(20,20,20), bty = "n", pt.cex = 1.5, cex = 0.8 ,
text.col = "black", horiz = FALSE, inset = c(0.0, 0.1))

NUMBER_OF_CLUSTERS = 2
color_darkpink = "#e75480"
CLUSTER_BRANCH_COLORS <- c("blue", "red", color_darkpink)[1:NUMBER_OF_CLUSTERS]
CLUSTER_LABEL_COLORS <- c("blue", "red", color_darkpink)[1:NUMBER_OF_CLUSTERS]
behavioralMatrixClustering <- as.matrix(clusteringDf)
rownames(behavioralMatrixClustering) <- paste0(dfActivity$ActivityName, " - #", persons)
distMatrix <- dist(behavioralMatrixClustering, method="manhattan", diag = T)
hresults <- distMatrix %>% hclust(method="average")
hc <- hresults %>%
as.dendrogram %>%
set("nodes_cex", NUMBER_OF_CLUSTERS) %>%
set("labels_col", value = CLUSTER_LABEL_COLORS, k=NUMBER_OF_CLUSTERS) %>%
# set("leaves_pch", 19) %>%
# set("leaves_col", value = c("gray"), k=NUMBER_OF_CLUSTERS) %>%
set("branches_k_color", value=CLUSTER_BRANCH_COLORS, k=NUMBER_OF_CLUSTERS)
plot(hc)
legend("topright",
title="Drive=Failure \nChange of Arousal",
legend = c("Accelerophobia" , "Normal"),
col = c("red", "blue"),
pch = c(20,20,20), bty = "n", pt.cex = 1.5, cex = 0.8 ,
text.col = "black", horiz = FALSE, inset = c(0.0, 0.1))

# Store clustering data
fPath <- str_interp("../data/processed/analysis/TT1_Drive_4_PP.csv")
dfx <- clusteringDf
dfx <- cbind(persons, behavioralDf$PP_before, dfx, dfActivity$ActivityName)
names(dfx) <- c("Subject", "PP_Prior", "PP_Dev", "Activity")
write.csv(dfx, fPath, row.names = F)
library(cluster)
fit <- kmeans(clusteringDf, 2)
clusplot(clusteringDf, fit$cluster, color=TRUE, shade=TRUE,
labels=2, lines=0)

silhouette_score <- function(k){
km <- kmeans(clusteringDf, centers = k, nstart=25)
ss <- silhouette(km$cluster, dist(clusteringDf))
mean(ss[, 3])
}
k <- 2:10
avg_sil <- sapply(k, silhouette_score)
plot(k, type='b', avg_sil, xlab='Number of clusters', ylab='Average Silhouette Scores', frame=FALSE)

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CnNvdXJjZSgnLi4vc2V0dGluZ3Mvc2V0dGluZ3MuUicpCnNvdXJjZSgnY29tbW9uRnVuY3Rpb25zLlInKQpgYGAKCmBgYHtyfQpwZXJzb25zIDwtIFNFTEVDVEVEX1NVQkpFQ1RTCgphbGxfRHJpdmU0IDwtIHJlYWQuY3N2KCcuLi9kYXRhL3Byb2Nlc3NlZC9kaXN0YW5jZXdpc2UvVFQxX0RyaXZlXzRfMzBtXzMwbS5jc3YnKQphbGxfRHJpdmU0JFN1YmplY3QgPC0gYXMuZmFjdG9yKGFsbF9Ecml2ZTQkU3ViamVjdCkKYWxsX0RyaXZlNCRsb2dQZXJzcGlyYXRpb24gPC0gbG9nKGFsbF9Ecml2ZTQkUGVyc3BpcmF0aW9uKQoKIyBzdGFydGluZ19wb2ludHMgPSBjKCA2NjkgLCA2NjggLCA2NzYgLCA2ODcgLCA2ODAgLCAgNjc2ICwgIDY3OCAsCiMgICAgICAgICAgICAgICAgICAgICAgNjkzICwgNzIyICwgNzIzICwgNjc3ICwgNjc5ICwgIDcxMSAsICA3MDcgLCAgCiMgICAgICAgICAgICAgICAgICAgICAgNjk5ICwgNjc5ICwgNjg0ICwgNjg4ICwgNjg2ICwgIDY5NiAsICA3MDIgKQojIAojIGVuZGluZ19wb2ludHMgICA9IGMoIDc0MSAsIDc4NiAsIDc0OSAsIDc4MiAsIDczNiAsICA3NTYgLCAgNzY4ICwgIAojICAgICAgICAgICAgICAgICAgICAgIDgxMiAsIDg1MyAsIDc5MiAsIDc4MyAsIDc3MiAsICA3OTkgLCAgNzgxICwgIAojICAgICAgICAgICAgICAgICAgICAgIDc3NyAsIDc2MyAsIDc5NSAsIDc5MSAsIDgzMiAsICA3NTUgLCAgNzU4ICkKCnBlYWtfcG9pbnRzICAgICA9IGMoIDY3ICwgIDg2ICwgIDczICwgIDczICwgIDczICwgIDY0ICwgIDczICwgIAogICAgICAgICAgICAgICAgICAgICA3OSAsICA2OSAsICA2NCAsICA2OCAsICA2NyAsICA3NyAsICA2OCAsICAKICAgICAgICAgICAgICAgICAgICAgODIgLCAgNjcgLCAgNzIgLCAgNzIgLCAgNzEgLCAgNjggLCAgNjQgKQoKIyBEcml2aW5nIHRpbWUKZHJpdmluZ190aW1lcyA9IHZlY3Rvcihtb2RlPSJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKHBlcnNvbnMpKQpuYW1lcyhkcml2aW5nX3RpbWVzKSA8LSBwZXJzb25zCgphY3Rpdml0eV9uYW1lcyA9IHZlY3Rvcihtb2RlPSJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKHBlcnNvbnMpKQpuYW1lcyhhY3Rpdml0eV9uYW1lcykgPC0gcGVyc29ucwoKYWNjX3N0YXJ0X3RpbWVzID0gdmVjdG9yKG1vZGU9Imxpc3QiLCBsZW5ndGggPSBsZW5ndGgocGVyc29ucykpCm5hbWVzKGFjY19zdGFydF90aW1lcykgPC0gcGVyc29ucwphY2NfZW5kX3RpbWVzID0gdmVjdG9yKG1vZGU9Imxpc3QiLCBsZW5ndGggPSBsZW5ndGgocGVyc29ucykpCm5hbWVzKGFjY19lbmRfdGltZXMpIDwtIHBlcnNvbnMKCnN0cmVzc29yX3N0YXJ0X3RpbWVzID0gdmVjdG9yKG1vZGU9Imxpc3QiLCBsZW5ndGggPSBsZW5ndGgocGVyc29ucykpCm5hbWVzKHN0cmVzc29yX3N0YXJ0X3RpbWVzKSA8LSBwZXJzb25zCnN0cmVzc29yX2VuZF90aW1lcyA9IHZlY3Rvcihtb2RlPSJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKHBlcnNvbnMpKQpuYW1lcyhzdHJlc3Nvcl9lbmRfdGltZXMpIDwtIHBlcnNvbnMKCmNvbXBsZXRlX3RpbWVzID0gdmVjdG9yKG1vZGU9Imxpc3QiLCBsZW5ndGggPSBsZW5ndGgocGVyc29ucykpCm5hbWVzKGNvbXBsZXRlX3RpbWVzKSA8LSBwZXJzb25zCgpkYXRhX2Jhc2VsaW5lID0gdmVjdG9yKG1vZGU9Imxpc3QiLCBsZW5ndGg9bGVuZ3RoKHBlcnNvbnMpKQpwcF9iYXNlbGluZSA9IHZlY3Rvcihtb2RlPSJsaXN0IiwgbGVuZ3RoPWxlbmd0aChwZXJzb25zKSkKCm5hbWVzKGRhdGFfYmFzZWxpbmUpIDwtIHBlcnNvbnMKbmFtZXMocHBfYmFzZWxpbmUpIDwtIHBlcnNvbnMKCiMgTnVtYmVyIG9mIHBlYWtzCgpQUkVWX0RJU1RBTkNFID0gNjAwClRSQUNLSU5HX0RJU1RBTkNFID0gMTUwCkRSSVZFX01PREUgPSA0CmBgYAoKYGBge3J9CmdldEFjdGl2aXR5TmFtZSA8LSBmdW5jdGlvbih4LCBmdWxsbmFtZT1GKSB7CiAgaWYoeCA9PSAxKSByZXR1cm4oaWZlbHNlKGZ1bGxuYW1lLCAiTm9ybWFsIiwgIk5PIikpCiAgaWYoeCA9PSAyKSByZXR1cm4oaWZlbHNlKGZ1bGxuYW1lLCAiQ29nbml0aXZlIiwgIkMiKSkKICBpZih4ID09IDMpIHJldHVybihpZmVsc2UoZnVsbG5hbWUsICJNb3RvcmljIiwgIk0iKSkKfQoKZm9yIChwIGluIHBlcnNvbnMpIHsKICBwRGF0YSA8LSBhbGxfRHJpdmU0W2FsbF9Ecml2ZTQkU3ViamVjdD09YXMuaW50ZWdlcihwKSB8IGFsbF9Ecml2ZTQkU3ViamVjdD09cCxdCiAgcEFjYyA8LSBwRGF0YVtwRGF0YSRGYWlsdXJlPjAuNSxdICMgRmFpbHVyZSA9IDEKICBhY2Nfc3RhcnRfdGltZXNbW3BdXSA8LSBtaW4ocEFjYyREaXN0YW5jZSkKICBhY2NfZW5kX3RpbWVzW1twXV0gPC0gbWF4KHBBY2MkRGlzdGFuY2UpCiAgCiAgYWN0aXZpdHlfbmFtZXNbW3BdXSA8LSBnZXRBY3Rpdml0eU5hbWUocERhdGFbcERhdGEkVGltZT09NjAsXSRBY3Rpdml0eSwgZnVsbG5hbWUgPSBUKQogIAogIHBTdHJlc3NvciA9IHBEYXRhW3BEYXRhJEFjdGl2aXR5PjEuNSxdICMgU3RyZXNzb3IgPSAyLCAzCiAgaWYgKG5yb3cocFN0cmVzc29yKSA+IDApIHsKICAgIHN0cmVzc29yX3N0YXJ0X3RpbWVzW1twXV0gPC0gbWluKHBTdHJlc3NvciREaXN0YW5jZSkKICAgIHN0cmVzc29yX2VuZF90aW1lc1tbcF1dIDwtIG1heChwU3RyZXNzb3IkRGlzdGFuY2UpCiAgfSBlbHNlIHsKICAgIHN0cmVzc29yX3N0YXJ0X3RpbWVzW1twXV0gPC0gTlVMTAogICAgc3RyZXNzb3JfZW5kX3RpbWVzW1twXV0gPC0gTlVMTAogIH0KfQpgYGAKCmBgYHtyfQppZHggPC0gMQpwbHRfQWxsQWNjIDwtIHZlY3Rvcihtb2RlPSJsaXN0IiwgbGVuZ3RoPWxlbmd0aChwZXJzb25zKSkgCm5hbWVzKHBsdF9BbGxBY2MpIDwtIHBlcnNvbnMKCkNPTE9SX0FDQyA9ICIjMDJBM0M4IgpDT0xPUl9QUCA9ICIjRjI4RThFIgpDT0xPUl9CUkFLRSA9ICIjODg4ODg4IgoKeTEgPC0gbGlzdCgKICB0aWNrZm9udCA9IGxpc3QoY29sb3IgPSBDT0xPUl9BQ0MpLAogIHRpdGxlPSJEZWdyZWUiLAogIHJhbmdlPWMoMCwgMTAwKQopCnkyIDwtIGxpc3QoCiAgdGlja2ZvbnQgPSBsaXN0KGNvbG9yID0gQ09MT1JfUFApLAogIG92ZXJsYXlpbmcgPSAieSIsCiAgc2lkZSA9ICJyaWdodCIsCiAgdGl0bGUgPSAiTG9nIFBlcnNwaXJhdGlvbiIsCiAgc2hvd2dyaWQgPSBGQUxTRSwKICByYW5nZT1jKG1pbihhbGxfRHJpdmU0JHBwTG9nTm9ybWFsaXplZCksIG1heChhbGxfRHJpdmU0JHBwTG9nTm9ybWFsaXplZCkpCikKICAKZm9yIChwIGluIHBlcnNvbnMpIHsKICBwRGF0YSA8LSBhbGxfRHJpdmU0W2FsbF9Ecml2ZTQkU3ViamVjdD09YXMuaW50ZWdlcihwKSB8IGFsbF9Ecml2ZTQkU3ViamVjdD09cCxdCiAgCiAgIyBCYXNlbGluZQogIGRhdGFfYmFzZWxpbmVbW3BdXSA8LSByZWFkLmNzdihzdHJfaW50ZXJwKCIuLi9kYXRhL3Byb2Nlc3NlZC9kcml2ZXMvVDAke3BlcnNvbn0vVDAke3BlcnNvbn1fRHJpdmVfMS5jc3YiLCBsaXN0KHBlcnNvbj1wKSkpCiAgIyBDb21wdXRlIHRoZSBtZWFuCiAgcF9wcF9uciA8LSBkYXRhX2Jhc2VsaW5lW1twXV0kUGVyc3BpcmF0aW9uCiAgcF9wcF9uciA8LSBwX3BwX25yWyFpcy5uYShwX3BwX25yKV0KICBwcF9iYXNlbGluZVtbcF1dIDwtIGxvZyhtZWFuKHBfcHBfbnIpKQogIAogICMgSW5jaWRlbnQKICBkcml2aW5nX3RpbWVzW1twXV0gPC0gbWF4KHBEYXRhJERpc3RhbmNlKQogIAogIGluY2lkZW50X3N0YXJ0aW5nX3RpbWUgPC0gYWNjX3N0YXJ0X3RpbWVzW1twXV0gIyBzdGFydGluZ19wb2ludHNbaWR4XQogIGluY2lkZW50X2VuZGluZ190aW1lIDwtIGFjY19lbmRfdGltZXNbW3BdXQogIGNvbXBsZXRlX3RpbWVzW1twXV0gPC0gaWZlbHNlKGluY2lkZW50X3N0YXJ0aW5nX3RpbWUgKyBUUkFDS0lOR19ESVNUQU5DRSA+IGRyaXZpbmdfdGltZXNbW3BdXSwgZHJpdmluZ190aW1lc1tbcF1dLCBpbmNpZGVudF9zdGFydGluZ190aW1lICsgVFJBQ0tJTkdfRElTVEFOQ0UpCiAgCiAgZnJvbV90aW1lIDwtIGlmZWxzZShpbmNpZGVudF9zdGFydGluZ190aW1lIC0gUFJFVl9ESVNUQU5DRSA+PSAwLCBpbmNpZGVudF9zdGFydGluZ190aW1lIC0gUFJFVl9ESVNUQU5DRSwgMCkKICB0b190aW1lIDwtIGNvbXBsZXRlX3RpbWVzW1twXV0KICAKICAjIHByaW50KHBhc3RlKCJGcm9tIiwgZnJvbV90aW1lKSkKICAjIHByaW50KHBhc3RlKCJJbmNpZGVudCIsIGluY2lkZW50X3N0YXJ0aW5nX3RpbWUpKQogICMgcHJpbnQocGFzdGUoIlRvIiwgdG9fdGltZSkpCiAgCiAgICAKICBwRGF0YUJlZm9yZSA8LSBwRGF0YVtwRGF0YSREaXN0YW5jZSA8IGluY2lkZW50X3N0YXJ0aW5nX3RpbWUgJiBwRGF0YSREaXN0YW5jZSA+PSBmcm9tX3RpbWUsXQogIHBEYXRhQWZ0ZXIgPC0gcERhdGFbcERhdGEkRGlzdGFuY2UgPj0gaW5jaWRlbnRfc3RhcnRpbmdfdGltZSAmIHBEYXRhJERpc3RhbmNlIDw9IHRvX3RpbWUsXQogIAogICMgcHJpbnQobnJvdyhwRGF0YUJlZm9yZSkpCiAgIyBwcmludChucm93KHBEYXRhQWZ0ZXIpKQogIAogIHBwTWVhbkJlZm9yZSA8LSBtZWFuKHBEYXRhQmVmb3JlJHBwTG9nTm9ybWFsaXplZCkKICBwcE1lYW5BZnRlciA8LSBtZWFuKHBEYXRhQWZ0ZXIkcHBMb2dOb3JtYWxpemVkKQogIAogIGRpci5jcmVhdGUoZmlsZS5wYXRoKCcuLi9maWd1cmVzL2RyaXZlLycsIHBhc3RlMCgnRHJpdmVfJywgRFJJVkVfTU9ERSkpLCBzaG93V2FybmluZ3MgPSBGQUxTRSkKICBmbmFtZSA8LSBzdHJfaW50ZXJwKCcuLi9maWd1cmVzL2RyaXZlL0RyaXZlXyR7ZHJpdmV9L1Ake3BlcnNvbn0uc3ZnJywgbGlzdChkcml2ZT1EUklWRV9NT0RFLCBwZXJzb249cCkpIAogIAogIHBEYXRhIDwtIHBEYXRhW3BEYXRhJERpc3RhbmNlID49IGZyb21fdGltZSxdCiAgcGxvdF9BY2MgPC0gcGxvdF9seShwRGF0YSwgeCA9IH5EaXN0YW5jZSwgaGVpZ2h0PTQwMCwgd2lkdGg9OTAwKSAlPiUKICAgICAgICAgICAgICBhZGRfdHJhY2UobmFtZT0iQWNjZWxlcmF0aW9uIiwgeSA9IH5BY2NlbGVyYXRpb24sIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMnLCBsaW5lPWxpc3Qod2lkdGg9MS41LCBjb2xvcj1DT0xPUl9BQ0MpKSAlPiUgCiAgICAgICAgICAgICAgYWRkX3RyYWNlKG5hbWU9IkJyYWtlIiwgeSA9IH5CcmFraW5nLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzJywgbGluZT1saXN0KHdpZHRoPTEuNSwgY29sb3I9Q09MT1JfQlJBS0UpKSAlPiUKICAgICAgICAgICAgICBhZGRfdHJhY2UobmFtZT0iUFAiLCB5ID0gfnBwTG9nTm9ybWFsaXplZCwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycsIGxpbmU9bGlzdCh3aWR0aD0xLjUsIGNvbG9yPUNPTE9SX1BQKSwgeWF4aXMgPSAieTIiKSAlPiUgCiAgICAgICAgICAgICAgYWRkX3NlZ21lbnRzKHggPSBtaW4ocERhdGEkRGlzdGFuY2UpLCB4ZW5kID0gbWF4KHBEYXRhJERpc3RhbmNlKSwgeSA9IHBwTWVhbkJlZm9yZSwgeWVuZCA9IHBwTWVhbkJlZm9yZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gInkyIiwgbmFtZT0iTWVhbiBQUCAoQmVmb3JlIEluY2lkZW50KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmU9bGlzdChjb2xvcj1DT0xPUl9QUCwgZGFzaCA9ICdkb3QnKSkgJT4lCiAgICAgICAgICAgICAgYWRkX3NlZ21lbnRzKHggPSBtaW4ocERhdGEkRGlzdGFuY2UpLCB4ZW5kID0gbWF4KHBEYXRhJERpc3RhbmNlKSwgeSA9IHBwTWVhbkFmdGVyLCB5ZW5kID0gcHBNZWFuQWZ0ZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9ICJ5MiIsIG5hbWU9Ik1lYW4gUFAgKEFmdGVyIEluY2lkZW50KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmU9bGlzdChjb2xvcj0iZGFya3JlZCIsIGRhc2ggPSAnZG90JykpICU+JQogICAgICAgICAgICAgICMgYWRkX3NlZ21lbnRzKHggPSBtaW4ocERhdGEkRGlzdGFuY2UpIC0gMC4xLCB4ZW5kID0gbWF4KHBEYXRhJERpc3RhbmNlKSwgeSA9IHBwX2Jhc2VsaW5lW1twXV0sIHllbmQgPSBwcF9iYXNlbGluZVtbcF1dLCAKICAgICAgICAgICAgICAjICAgICAgICAgICAgICB5YXhpcyA9ICJ5MiIsIG5hbWU9IkJhc2VsaW5lIFBQIChmcm9tIERyaXZlIDEpIiwKICAgICAgICAgICAgICAjICAgICAgICAgICAgICBsaW5lPWxpc3QoY29sb3I9ImJsdWUiLCBkYXNoID0gJ2RvdCcpKSAlPiUKICAgIAogICAgICAgICAgICAgIGxheW91dCgKICAgICAgICAgICAgICAgIHRpdGxlPXBhc3RlMCgiU3ViamVjdCAjIiwgcCwgIiAoU3RyZXNzb3I9IiwgYWN0aXZpdHlfbmFtZXNbW3BdXSwgIikiKSwgCiAgICAgICAgICAgICAgICB4YXhpcz1saXN0KHRpdGxlPSJEaXN0YW5jZSBbbV0iLCByYW5nZT1jKDApKSwgCiAgICAgICAgICAgICAgICB5YXhpcz15MSwgCiAgICAgICAgICAgICAgICB5YXhpczI9eTIsIAogICAgICAgICAgICAgICAgbWFyZ2luID0gbGlzdChsID0gNTAsIHIgPSA1MCwgYiA9IDUwLCB0ID0gNTAsIHBhZCA9IDQpLAogICAgICAgICAgICAgICAgc2hhcGVzID0gbGlzdCgKICAgICAgICAgICAgICAgICAgIyBIb2xpc3RpYyBwZXJpb2QKICAgICAgICAgICAgICAgICAgbGlzdCh0eXBlID0gInJlY3QiLCBmaWxsY29sb3IgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAicmVkIiksIG9wYWNpdHkgPSAwLjMsCiAgICAgICAgICAgICAgICAgICAgICB4MCA9IGluY2lkZW50X3N0YXJ0aW5nX3RpbWUsIHgxID0gaW5jaWRlbnRfZW5kaW5nX3RpbWUsIHhyZWYgPSAieCIsCiAgICAgICAgICAgICAgICAgICAgICB5MCA9IDAsIHkxID0gMTAwLCB5cmVmID0gInkiKSwKICAgICAgICAgICAgICAgICAgIyBTdHJlc3NvciBwZXJpb2QKICAgICAgICAgICAgICAgICAgbGlzdCh0eXBlID0gInJlY3QiLCBmaWxsY29sb3IgPSAieWVsbG93IiwgCiAgICAgICAgICAgICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAieWVsbG93IiksIG9wYWNpdHkgPSAwLjEsCiAgICAgICAgICAgICAgICAgICAgICB4MCA9IHN0cmVzc29yX3N0YXJ0X3RpbWVzW1twXV0sIHgxID0gaW5jaWRlbnRfc3RhcnRpbmdfdGltZSwgeHJlZiA9ICJ4IiwKICAgICAgICAgICAgICAgICAgICAgIHkwID0gMCwgeTEgPSAxMDAsIHlyZWYgPSAieSIpLAogICAgICAgICAgICAgICAgICBsaXN0KHR5cGUgPSAicmVjdCIsIGZpbGxjb2xvciA9ICJ5ZWxsb3ciLCAKICAgICAgICAgICAgICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJ5ZWxsb3ciKSwgb3BhY2l0eSA9IDAuMSwKICAgICAgICAgICAgICAgICAgICAgIHgwID0gaW5jaWRlbnRfZW5kaW5nX3RpbWUsIHgxID0gc3RyZXNzb3JfZW5kX3RpbWVzW1twXV0sIHhyZWYgPSAieCIsCiAgICAgICAgICAgICAgICAgICAgICB5MCA9IDAsIHkxID0gMTAwLCB5cmVmID0gInkiKQogICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgIGxlZ2VuZCA9IGxpc3QoeCA9IDAuMSwgeSA9IDEsIGJnY29sb3IgPSAicmdiYSgwLDAsMCwwKSIsIHRpdGxlPSJNZXRyaWMiKSwKICAgICAgICAgICAgICAgIGF1dG9zaXplID0gRgogICAgICAgICAgICAgICkKICAKICAjIG9yY2EocGxvdF9QUCwgZm5hbWUpCiAgaWR4IDwtIGlkeCArIDEKICBwbHRfQWxsQWNjW1twXV0gPC0gcGxvdF9BY2MKfQoKaHRtbHRvb2xzOjp0YWdMaXN0KHBsdF9BbGxBY2MpCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CiMgZm9yIChwIGluIHBlcnNvbnMpIHsKIyAgICMgU2F2ZSBpbWFnZQojICAgb3JjYShwbHRfQWxsQWNjW1twXV0sIGZpbGUgPSBwYXN0ZTAoIi4uL3Bsb3RzL2RyaXZlL0RyaXZlXzQvVDAiLCBwLCAiLnBuZyIpLCBzY2FsZSA9IDIpCiMgfQpgYGAKCmBgYHtyfQppZHggPC0gMQpiZWhhdmlvcmFsQ29sdW1ucyA8LSBjKCJTdWJqZWN0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIkJyYWtlX3UiLCAKICAgICAgICAgICAgICAgICAgICAgICAiQnJha2Vfc3RkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIlBQX2JlZm9yZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIlBQX3UiLCAgCiAgICAgICAgICAgICAgICAgICAgICAgIlBQX3N0ZCIsCiAgICAgICAgICAgICAgICAgICAgICAgIlBQX2RldiIpCmJlaGF2aW9yYWxNYXRyaXggPC0gbWF0cml4KG5yb3c9bGVuZ3RoKHBlcnNvbnMpLCBuY29sID0gbGVuZ3RoKGJlaGF2aW9yYWxDb2x1bW5zKSkKCiMgQ2FyZWZ1bCBhYm91dCBTdWJqZWN0IDA5CiMgc2VsZWN0ZWRfcGVyc29ucyA8LSBwZXJzb25zW3BlcnNvbnMgIT0gIjA5Il0KCmZvciAocCBpbiBwZXJzb25zKSB7CiAgcERhdGEgPC0gYWxsX0RyaXZlNFthbGxfRHJpdmU0JFN1YmplY3Q9PWFzLmludGVnZXIocCkgfCBhbGxfRHJpdmU0JFN1YmplY3Q9PXAsXQogIAogIGluY2lkZW50X3N0YXJ0aW5nX3RpbWUgPC0gYWNjX3N0YXJ0X3RpbWVzW1twXV0gIyBzdGFydGluZ19wb2ludHNbaWR4XQogIGluY2lkZW50X2VuZGluZ190aW1lIDwtIGFjY19lbmRfdGltZXNbW3BdXQogIAogIGZyb21fdGltZSA8LSBpZmVsc2UoaW5jaWRlbnRfc3RhcnRpbmdfdGltZSAtIFBSRVZfRElTVEFOQ0UgPj0gMCwgaW5jaWRlbnRfc3RhcnRpbmdfdGltZSAtIFBSRVZfRElTVEFOQ0UsIDApCiAgdG9fdGltZSA8LSBjb21wbGV0ZV90aW1lc1tbcF1dCiAgICAKICBkZkJlZm9yZSA8LSBwRGF0YVtwRGF0YSREaXN0YW5jZSA8IGluY2lkZW50X3N0YXJ0aW5nX3RpbWUgJiBwRGF0YSREaXN0YW5jZSA+PSBmcm9tX3RpbWUsXQogIGRmQWZ0ZXIgPC0gcERhdGFbcERhdGEkRGlzdGFuY2UgPj0gaW5jaWRlbnRfc3RhcnRpbmdfdGltZSAmIHBEYXRhJERpc3RhbmNlIDw9IHRvX3RpbWUsXQogIAogICMgZGlmZlNwZWVkIDwtIG1lYW4oZGZBZnRlciRTcGVlZCkgLSBtZWFuKGRmQmVmb3JlJFNwZWVkKQogIGJyYWtlTWVhbiA8LSBtZWFuKGRmQWZ0ZXIkQnJha2luZykKICBicmFrZVN0ZCA8LSBtZWFuKGRmQWZ0ZXIkQnJha2luZykKICAKICBwcE1lYW4gPC0gbWVhbihkZkFmdGVyJHBwTG9nTm9ybWFsaXplZCkKICBwcEJlZm9yZSA8LSBtZWFuKGRmQmVmb3JlJHBwTG9nTm9ybWFsaXplZCkKICBwcFN0ZCA8LSBzZChkZkFmdGVyJHBwTG9nTm9ybWFsaXplZCkKICAKICBtaWRfYXZnIDwtIChwcF9iYXNlbGluZVtbcF1dICsgbWVhbihkZkJlZm9yZSRwcExvZ05vcm1hbGl6ZWQpKSAvIDIKICAgIAogIGRpZmZQUCA8LSBtZWFuKGRmQWZ0ZXIkcHBMb2dOb3JtYWxpemVkKSAtIG1lYW4oZGZCZWZvcmUkcHBMb2dOb3JtYWxpemVkKQogIAogIGJlaGF2aW9yYWxNYXRyaXhbaWR4LCBdIDwtIGMocCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3VuZChicmFrZU1lYW4sIGRpZ2l0cz01KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3VuZChicmFrZVN0ZCwgZGlnaXRzPTUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQocHBCZWZvcmUsIGRpZ2l0cz01KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKHBwTWVhbiwgZGlnaXRzID0gNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3VuZChwcFN0ZCwgZGlnaXRzPTUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQoZGlmZlBQLCBkaWdpdHM9NSkpCiAgaWR4IDwtIGlkeCArIDEKfQoKIyBiZWhhdmlvcmFsTWF0cml4CgpiZWhhdmlvcmFsRGYgPC0gYXMuZGF0YS5mcmFtZShiZWhhdmlvcmFsTWF0cml4KQpuYW1lcyhiZWhhdmlvcmFsRGYpIDwtIGJlaGF2aW9yYWxDb2x1bW5zCgpiZWhhdmlvcmFsRGYKCmBgYAoKCmBgYHtyfQpjbHVzdGVyaW5nRGYgPC0gYmVoYXZpb3JhbERmCmNsdXN0ZXJpbmdEZiRTdWJqZWN0IDwtIE5VTEwKIyBjbHVzdGVyaW5nRGYkUFBfZGV2X25vcm0gPC0gYXMubnVtZXJpYyhjbHVzdGVyaW5nRGYkUFBfZGV2KSAvIGFzLm51bWVyaWMoY2x1c3RlcmluZ0RmJFBQX3UpCiMgY2x1c3RlcmluZ0RmJFBQX3N0ZF9ub3JtIDwtIGFzLm51bWVyaWMoY2x1c3RlcmluZ0RmJFBQX3N0ZCkgLyBhcy5udW1lcmljKGNsdXN0ZXJpbmdEZiRQUF91KQpjbHVzdGVyaW5nRGYkQnJha2VfdSA8LSBOVUxMCmNsdXN0ZXJpbmdEZiRCcmFrZV9zdGQgPC0gTlVMTApjbHVzdGVyaW5nRGYkUFBfYmVmb3JlIDwtIE5VTEwKY2x1c3RlcmluZ0RmJFBQX3UgPC0gTlVMTApjbHVzdGVyaW5nRGYkUFBfc3RkIDwtIE5VTEwKIyBjbHVzdGVyaW5nRGYkUFBfZGV2IDwtIE5VTEwKCnJvd25hbWVzKGNsdXN0ZXJpbmdEZikgPC0gcGFzdGUwKCIjIiwgcGVyc29ucykKCmZvciAoY29sIGluIG5hbWVzKGNsdXN0ZXJpbmdEZikpIHsKICBjbHVzdGVyaW5nRGZbLGNvbF0gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoY2x1c3RlcmluZ0RmWywgY29sXSkpCiAgIyBjbHVzdGVyaW5nRGZbLGNvbF0gPC0gc2NhbGUoY2x1c3RlcmluZ0RmWyxjb2xdKQp9CmNsdXN0ZXJpbmdEZgpgYGAKCmBgYHtyfQpkZkFjdGl2aXR5IDwtIGFsbF9Ecml2ZTRbYWxsX0RyaXZlNCRUaW1lPT02MCxdICU+JSBzZWxlY3QoYygiU3ViamVjdCIsICJBY3Rpdml0eSIpKQpkZkFjdGl2aXR5JEFjdGl2aXR5TmFtZSA8LSBzYXBwbHkoZGZBY3Rpdml0eSRBY3Rpdml0eSwgZ2V0QWN0aXZpdHlOYW1lKQpkZkFjdGl2aXR5JFN1YmplY3QgPC0gYXMuZmFjdG9yKGRmQWN0aXZpdHkkU3ViamVjdCkKcm93bmFtZXMoZGZBY3Rpdml0eSkgPC0gTlVMTApkZkFjdGl2aXR5ICU+JSBzZWxlY3QoYygiU3ViamVjdCIsICJBY3Rpdml0eU5hbWUiKSkKYGBgCgpgYGB7cn0KbGlicmFyeShkZW5kZXh0ZW5kKQoKTlVNQkVSX09GX0NMVVNURVJTID0gMwoKY29sb3JfZGFya3BpbmsgPSAiI2U3NTQ4MCIKQ0xVU1RFUl9CUkFOQ0hfQ09MT1JTIDwtIGMoImJsdWUiLCAicmVkIiwgY29sb3JfZGFya3BpbmspWzE6TlVNQkVSX09GX0NMVVNURVJTXQpDTFVTVEVSX0xBQkVMX0NPTE9SUyA8LSBjKCJibHVlIiwgInJlZCIsIGNvbG9yX2RhcmtwaW5rKVsxOk5VTUJFUl9PRl9DTFVTVEVSU10KCmJlaGF2aW9yYWxNYXRyaXhDbHVzdGVyaW5nIDwtIGFzLm1hdHJpeChjbHVzdGVyaW5nRGYpCnJvd25hbWVzKGJlaGF2aW9yYWxNYXRyaXhDbHVzdGVyaW5nKSA8LSBwYXN0ZTAoZGZBY3Rpdml0eSRBY3Rpdml0eU5hbWUsICIgLSAjIiwgcGVyc29ucykKZGlzdE1hdHJpeCA8LSBkaXN0KGJlaGF2aW9yYWxNYXRyaXhDbHVzdGVyaW5nLCBtZXRob2Q9Im1hbmhhdHRhbiIpCmhyZXN1bHRzIDwtIGRpc3RNYXRyaXggJT4lIGhjbHVzdAoKaGMgPC0gaHJlc3VsdHMgJT4lIAogICAgICBhcy5kZW5kcm9ncmFtICU+JQogICAgICBzZXQoIm5vZGVzX2NleCIsIE5VTUJFUl9PRl9DTFVTVEVSUykgJT4lCiAgICAgIHNldCgibGFiZWxzX2NvbCIsIHZhbHVlID0gQ0xVU1RFUl9MQUJFTF9DT0xPUlMsIGs9TlVNQkVSX09GX0NMVVNURVJTKSAlPiUKICAgICAgIyBzZXQoImxlYXZlc19wY2giLCAxOSkgJT4lCiAgICAgICMgc2V0KCJsZWF2ZXNfY29sIiwgdmFsdWUgPSBjKCJncmF5IiksIGs9TlVNQkVSX09GX0NMVVNURVJTKSAlPiUgICAgCiAgICAgIHNldCgiYnJhbmNoZXNfa19jb2xvciIsIHZhbHVlPUNMVVNURVJfQlJBTkNIX0NPTE9SUywgaz1OVU1CRVJfT0ZfQ0xVU1RFUlMpCgpwbG90KGhjKQpsZWdlbmQoInRvcHJpZ2h0IiwgCiAgICAgdGl0bGU9IkRyaXZlPUZhaWx1cmUgXG5DaGFuZ2Ugb2YgQXJvdXNhbCIsCiAgICAgbGVnZW5kID0gYygiRXhjZXB0aW9uYWwgSW5jcmVhc2UiICwgIk5vdGljYWJsZSBJbmNyZWFzZSIgLCAiTm8tY2hhbmdlIG9yIERlY3JlYXNlIiksIAogICAgIGNvbCA9IGMoInJlZCIsICJwaW5rIiAsICJibHVlIiksCiAgICAgcGNoID0gYygyMCwyMCwyMCksIGJ0eSA9ICJuIiwgIHB0LmNleCA9IDEuNSwgY2V4ID0gMC44ICwgCiAgICAgdGV4dC5jb2wgPSAiYmxhY2siLCBob3JpeiA9IEZBTFNFLCBpbnNldCA9IGMoMC4wLCAwLjEpKQpgYGAKCmBgYHtyfQpOVU1CRVJfT0ZfQ0xVU1RFUlMgPSAyCgpjb2xvcl9kYXJrcGluayA9ICIjZTc1NDgwIgpDTFVTVEVSX0JSQU5DSF9DT0xPUlMgPC0gYygiYmx1ZSIsICJyZWQiLCBjb2xvcl9kYXJrcGluaylbMTpOVU1CRVJfT0ZfQ0xVU1RFUlNdCkNMVVNURVJfTEFCRUxfQ09MT1JTIDwtIGMoImJsdWUiLCAicmVkIiwgY29sb3JfZGFya3BpbmspWzE6TlVNQkVSX09GX0NMVVNURVJTXQoKYmVoYXZpb3JhbE1hdHJpeENsdXN0ZXJpbmcgPC0gYXMubWF0cml4KGNsdXN0ZXJpbmdEZikKcm93bmFtZXMoYmVoYXZpb3JhbE1hdHJpeENsdXN0ZXJpbmcpIDwtIHBhc3RlMChkZkFjdGl2aXR5JEFjdGl2aXR5TmFtZSwgIiAtICMiLCBwZXJzb25zKQpkaXN0TWF0cml4IDwtIGRpc3QoYmVoYXZpb3JhbE1hdHJpeENsdXN0ZXJpbmcsIG1ldGhvZD0ibWFuaGF0dGFuIiwgZGlhZyA9IFQpCmhyZXN1bHRzIDwtIGRpc3RNYXRyaXggJT4lIGhjbHVzdChtZXRob2Q9ImF2ZXJhZ2UiKQoKaGMgPC0gaHJlc3VsdHMgJT4lIAogICAgICBhcy5kZW5kcm9ncmFtICU+JQogICAgICBzZXQoIm5vZGVzX2NleCIsIE5VTUJFUl9PRl9DTFVTVEVSUykgJT4lCiAgICAgIHNldCgibGFiZWxzX2NvbCIsIHZhbHVlID0gQ0xVU1RFUl9MQUJFTF9DT0xPUlMsIGs9TlVNQkVSX09GX0NMVVNURVJTKSAlPiUKICAgICAgIyBzZXQoImxlYXZlc19wY2giLCAxOSkgJT4lCiAgICAgICMgc2V0KCJsZWF2ZXNfY29sIiwgdmFsdWUgPSBjKCJncmF5IiksIGs9TlVNQkVSX09GX0NMVVNURVJTKSAlPiUgICAgCiAgICAgIHNldCgiYnJhbmNoZXNfa19jb2xvciIsIHZhbHVlPUNMVVNURVJfQlJBTkNIX0NPTE9SUywgaz1OVU1CRVJfT0ZfQ0xVU1RFUlMpCgpwbG90KGhjKQpsZWdlbmQoInRvcHJpZ2h0IiwgCiAgICAgdGl0bGU9IkRyaXZlPUZhaWx1cmUgXG5DaGFuZ2Ugb2YgQXJvdXNhbCIsCiAgICAgbGVnZW5kID0gYygiQWNjZWxlcm9waG9iaWEiICwgIk5vcm1hbCIpLCAKICAgICBjb2wgPSBjKCJyZWQiLCAiYmx1ZSIpLAogICAgIHBjaCA9IGMoMjAsMjAsMjApLCBidHkgPSAibiIsICBwdC5jZXggPSAxLjUsIGNleCA9IDAuOCAsIAogICAgIHRleHQuY29sID0gImJsYWNrIiwgaG9yaXogPSBGQUxTRSwgaW5zZXQgPSBjKDAuMCwgMC4xKSkKYGBgCgpgYGB7cn0KIyBTdG9yZSBjbHVzdGVyaW5nIGRhdGEKZlBhdGggPC0gc3RyX2ludGVycCgiLi4vZGF0YS9wcm9jZXNzZWQvYW5hbHlzaXMvVFQxX0RyaXZlXzRfUFAuY3N2IikKZGZ4IDwtIGNsdXN0ZXJpbmdEZgpkZnggPC0gY2JpbmQocGVyc29ucywgYmVoYXZpb3JhbERmJFBQX2JlZm9yZSwgZGZ4LCBkZkFjdGl2aXR5JEFjdGl2aXR5TmFtZSkKbmFtZXMoZGZ4KSA8LSBjKCJTdWJqZWN0IiwgIlBQX1ByaW9yIiwgIlBQX0RldiIsICJBY3Rpdml0eSIpCndyaXRlLmNzdihkZngsIGZQYXRoLCByb3cubmFtZXMgPSBGKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGNsdXN0ZXIpCmZpdCA8LSBrbWVhbnMoY2x1c3RlcmluZ0RmLCAyKQpjbHVzcGxvdChjbHVzdGVyaW5nRGYsIGZpdCRjbHVzdGVyLCBjb2xvcj1UUlVFLCBzaGFkZT1UUlVFLAogICBsYWJlbHM9MiwgbGluZXM9MCkKYGBgCgpgYGB7cn0Kc2lsaG91ZXR0ZV9zY29yZSA8LSBmdW5jdGlvbihrKXsKICBrbSA8LSBrbWVhbnMoY2x1c3RlcmluZ0RmLCBjZW50ZXJzID0gaywgbnN0YXJ0PTI1KQogIHNzIDwtIHNpbGhvdWV0dGUoa20kY2x1c3RlciwgZGlzdChjbHVzdGVyaW5nRGYpKQogIG1lYW4oc3NbLCAzXSkKfQprIDwtIDI6MTAKYXZnX3NpbCA8LSBzYXBwbHkoaywgc2lsaG91ZXR0ZV9zY29yZSkKcGxvdChrLCB0eXBlPSdiJywgYXZnX3NpbCwgeGxhYj0nTnVtYmVyIG9mIGNsdXN0ZXJzJywgeWxhYj0nQXZlcmFnZSBTaWxob3VldHRlIFNjb3JlcycsIGZyYW1lPUZBTFNFKQpgYGAKCgo=